﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml.Linq;

namespace HigLabo.Net.SugarSync
{
    /// <summary>
    /// 
    /// </summary>
    public partial class SugarSyncClient
    {
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Boolean Authenticate()
        {
            _AuthorizationToken = "";
            var token = GetAuthorizationToken();
            if (token == null)
            {
                return false;
            }
            _AuthorizationToken = token;
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public String GetAuthorizationToken()
        {
            var sb = new StringBuilder(1024);
            var cl = new HttpClient();
            var cm = CreateGetAuthorizationTokenCommand();

            try
            {
                var res = cl.GetResponse(cm);
                return res.Headers["Location"];
            }
            catch
            {
                return null;
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public User GetUserInfo()
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, SugarSyncUrl.User);
            return new User(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public CollectionContents GetCollections(GetCollectionsCommand command)
        {
            var d = command.GetXmlData();
            var xml = GetResponseBodyText(HttpMethodName.Get,
                                          HttpClient.CreateQueryString(command.Url, d));
            return new CollectionContents(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Workspace GetWorkspace(GetWorkspacesCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new Workspace(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Workspace UpdateWorkspaceName(UpdateWorkspaceNameCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Put, command.Url, command);
            return new Workspace(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Folder GetFolder(GetFoldersCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new Folder(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String CreateFolder(CreateFoldersCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Post, command.Url, command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String DeleteFolder(DeleteFoldersCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Delete, command.Url, command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String UpdateFolderName(UpdateFolderNameCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Put, command.Url, command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public ReceivedShareCollection GetReceivedShares(GetReceivedSharesCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new ReceivedShareCollection(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File GetFile(GetFileCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new File(XElement.Parse(xml)) { Ref = command.Url };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String CreateFile(CreateFileCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Post, command.Url, command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File UpdateFile(UpdateFileCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Put, command.Url, command);
            return new File(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String DeleteFile(DeleteFileCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Delete, command.Url);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String CopyFile(CopyFileCommand command)
        {
            return this.GetResponseBodyText(HttpMethodName.Post, command.Url, command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Byte[] GetFileData(GetFileDataCommand command)
        {
            var xml = GetHttpWebResponse(HttpMethodName.Get, command.Url);
            return xml.ToByteArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String PutFileData(PutFileDataCommand command)
        {
            var cl = new HttpClient();
            var cm = new HttpRequestCommand(command.Url);
            var boundary = PutFileDataCommand.GetBoundaryString();
            cm.Headers["Authorization"] = _AuthorizationToken;
            cm.MethodName = HttpMethodName.Put;
            cm.ContentType = "multipart/form-data; boundary=\"" + boundary + "\"";
            cm.SetBodyStream(command.CreatePostData(boundary));
            var res = cl.GetResponse(cm);
            return res.BodyText;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public FileVersions GetVersionHistory(GetVersionHistoryCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url + "/version");
            return new FileVersions(XElement.Parse(xml));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public File CreatePublicLink(PublicLinkCommand command)
        {
            command.PublicLink = true;
            var xml = GetResponseBodyText(HttpMethodName.Put, command.Url, command);
            return new File(XElement.Parse(xml)) { Ref = command.Url };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File DestroyPublicLink(PublicLinkCommand command)
        {
            command.PublicLink = false;
            var xml = GetResponseBodyText(HttpMethodName.Put, command.Url, command);
            return new File(XElement.Parse(xml)) { Ref = command.Url };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Albums GetAlbum(GetAlbumsCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new Albums(XElement.Parse(xml)) { Ref = command.Url };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public CollectionContents GetAlbumsCollectionContents(GetAlbumsCollectionCommand command)
        {
            var xml = GetResponseBodyText(HttpMethodName.Get, command.Url);
            return new CollectionContents(XElement.Parse(xml));
        }
 
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        private String GetResponseBodyText(HttpMethodName methodName, String url)
        {
            return GetResponseBodyText(methodName, url, (SugarSyncCommand) null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private String GetResponseBodyText(HttpMethodName methodName, String url, SugarSyncCommand command)
        {
            var cl = new HttpClient();
            var cm = new HttpRequestCommand(url);

            cl.ResponseEncoding = Encoding.UTF8;
            
            cm.MethodName = methodName;
            cm.Headers["Authorization"] = _AuthorizationToken;

            HttpResponse rs;
            if (command == null)
            {
                rs = cl.GetResponse(cm);
            }
            else
            {
                var d = command.GetXmlData();
                cm.SetBodyStream(Encoding.UTF8.GetBytes(d.ToString()));
                rs = cl.GetResponse(cm);
            }
            return rs.BodyText;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        private Stream GetHttpWebResponse(HttpMethodName methodName, String url)
        {
            return GetHttpWebResponse(methodName, url, (SugarSyncCommand) null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="url"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private Stream GetHttpWebResponse(HttpMethodName methodName, String url, SugarSyncCommand command)
        {
            if (methodName == HttpMethodName.Put || methodName == HttpMethodName.Delete)
            {
                throw new ArgumentException();
            }

            var cl = new HttpClient();
            var cm = new HttpRequestCommand(url);
            cm.MethodName = methodName;
            cm.Headers["Authorization"] = _AuthorizationToken;

            HttpWebResponse rs;
            if (command == null)
            {
                rs = cl.GetHttpWebResponse(cm);
            }
            else
            {
                var d = command.GetXmlData();
                cm.SetBodyStream(Encoding.UTF8.GetBytes(d.ToString()));
                rs = cl.GetHttpWebResponse(cm);
            }
            return rs.GetResponseStream();
        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns></returns>
        //public Metadata GetRootFolder()
        //{
        //    return this.GetMetadata("/");
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns></returns>
        //public List<Metadata> GetRootItems()
        //{
        //    var md = this.GetMetadata("/");
        //    return md.Contents;
        //}
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns></returns>
        //public List<Metadata> GetRootFolders()
        //{
        //    var md = this.GetMetadata("/");
        //    md.Contents.RemoveAll(el => el.IsDirectory == false);
        //    return md.Contents;
        //}
    }
}